//////////////////////////////////////////////////////////////////////
//
//  CryEngine Source code
//	
//	File: AnimationManager.h
//  Implementation of Animation Manager.h
//
//	History:
//	January 12, 2005: Created by Ivo Herzeg <ivo@crytek.de>
//
//////////////////////////////////////////////////////////////////////

#ifndef _CRYTEK_GAHAIM_
#define _CRYTEK_GAHAIM_

#include "GlobalAnimationHeader.h"
#include "Controller.h"
#include "ControllerPQLog.h"
#include "ControllerTCB.h"

#include "IStreamEngine.h"
#include <NameCRCHelper.h>

#define AIM_POSES (1)
#define PRECISION (0.001)

class CModelSkeleton;

struct AimIKPose
{
	DynArray<Quat> m_arrRotation;
	DynArray<Vec3> m_arrPosition;

	void GetMemoryUsage( ICrySizer *pSizer ) const
	{
		pSizer->AddObject(m_arrRotation);
		pSizer->AddObject(m_arrPosition);
	}
};


struct QuadIndices 
{ 
	uint8 i0,i1,i2,i3; 
	Vec4	w0,w1,w2,w3;
	ColorB col;
	Vec3 height;
};



//////////////////////////////////////////////////////////////////////////
// this is the animation information on the module level (not on the per-model level)
// it doesn't know the name of the animation (which is model-specific), but does know the file name
// Implements some services for bone binding and ref counting
struct GlobalAnimationHeaderAIM : public GlobalAnimationHeader
{
	friend class CAnimationManager;
	friend class CAnimationSet;

	GlobalAnimationHeaderAIM ()
	{
		m_FilePathCRC32		=	0;
		m_nRef_by_Model		= 0;
		m_nRef_at_Runtime = 0;
		m_nTouchedCounter = 0;

		m_fStartSec				= -1;		// Start time in seconds.
		m_fEndSec					= -1;		// End time in seconds.
		m_fTotalDuration	= -1;		//asset-features

		m_nControllers	= 0;
		m_AnimTokenCRC32= 0;

		m_nExist				=	0;
	}


	virtual ~GlobalAnimationHeaderAIM()
	{
		ClearControllers();
	};


	const char* GetFilePath() const {	return m_FilePath.c_str(); };
	int GetFilePathCRC32() { return m_FilePathCRC32; }
	void SetFilePath(const string& name) 
	{ 
		m_FilePath = name; 
		m_FilePathCRC32 = NameCRCHelper::GetCRC(name.c_str()); 
	};


	void AddRef()
	{
		++m_nRef_by_Model;
	}

	void Release()
	{
		if (!--m_nRef_by_Model)
		{
			m_nControllers = 0;
			m_arrController.clear();
		}
	}


#ifdef _DEBUG
	// returns the maximum reference counter from all controllers. 1 means that nobody but this animation
	// structure refers to them
	int MaxControllerRefCount()
	{
		if (m_arrController.size()==0)
			return 0;
		int nMax = m_arrController[0]->NumRefs();
		for (int i=0; i<m_nControllers; ++i)
			if (m_arrController[i]->NumRefs() > nMax)
				nMax = m_arrController[i]->NumRefs();
		return nMax;
	}
#endif


	ILINE uint32 IsAssetLoaded() const 
	{ 
		return m_nControllers;
	}
	ILINE uint32 IsAssetOnDemand() const 
	{ 
		return 0;
	}

	//---------------------------------------------------------------
	IController* GetControllerByJointCRC32(uint32 nControllerID)
	{
		assert(m_nControllers);
		for (uint32 i=0; i<m_nControllers; i++)
		{
			uint32 nCID = m_arrController[i]->GetID();
			if (nControllerID==nCID)
				return m_arrController[i];
		}
		return 0;
	}

	f32 NTime2KTime( f32 ntime)
	{
		ntime = min(ntime, 1.0f);
		assert(ntime>=0 && ntime<=1);
		f32 duration	=	m_fEndSec-m_fStartSec;		
		f32 start			=	m_fStartSec;		
		f32 key				= (ntime*TICKS_PER_SECOND*duration  + start*TICKS_PER_SECOND);///40.0f;
		return key;
	}

	//count how many position controllers this animation has
	uint32 GetTolalPosKeys() const
	{
		uint32 pos=0;
		for (uint32 i=0; i<m_nControllers; i++)
			pos += (m_arrController[i]->GetPositionKeysNum()!=0);
		return pos;
	}

	//count how many rotation controllers this animation has
	uint32 GetTolalRotKeys() const
	{
		uint32 rot = 0;
		for (uint32 i=0; i<m_nControllers; i++)
			rot += (m_arrController[i]->GetRotationKeysNum()!=0);
		return rot;
	}

	size_t SizeOfAIM() const
	{
		size_t nSize = 0;//sizeof(*this);
		size_t nTemp00 = m_FilePath.capacity();					nSize += nTemp00;
		size_t nTemp08 = m_arrAimIKPosesAIM.get_alloc_size();				nSize += nTemp08;
		uint32 numAimPoses = m_arrAimIKPosesAIM.size();
		for(size_t i=0; i<numAimPoses; ++i)
		{
			nSize += m_arrAimIKPosesAIM[i].m_arrRotation.get_alloc_size();
			nSize += m_arrAimIKPosesAIM[i].m_arrPosition.get_alloc_size();
		}

		size_t nTemp09 = m_arrController.get_alloc_size();							nSize += nTemp09;
		for (uint16 i = 0; i < m_nControllers; ++i)
			nSize += m_arrController[i]->SizeOfController();
		return nSize;
	}

	void GetMemoryUsage(ICrySizer *pSizer) const
	{
		pSizer->AddObject( m_FilePath );
		pSizer->AddObject( m_arrController );
		pSizer->AddObject( m_arrAimIKPosesAIM );		
		
		for( int i = 0 ; i < m_nControllers ; ++i )
			pSizer->AddObject( m_arrController[i].get() );
	}


	size_t GetControllersCount() 
	{
		return m_nControllers;
	}

	void ClearControllers() 
	{
		ClearAssetRequested();
		m_nControllers = 0;
		m_arrController.clear();
	}


	uint32 LoadAIM();
	bool LoadChunks(IChunkFile* pChunkFile);
	bool ReadMotionParameters (IChunkFile::ChunkDesc *pChunkDesc  );
	bool ReadController( IChunkFile::ChunkDesc *pChunkDesc, uint32 bLoadOldChunks );
	bool ReadTiming (  IChunkFile::ChunkDesc *pChunkDesc );

	void ProcessAimPoses(CCharacterModel* pModel,DynArray<DirectionalBlends>& rDirBlends,DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos ); 




	Vec3 Debug_PolarCoordinate(const Quat& q);
	uint32 Debug_AnnotateExamples2(uint32 numPoses, QuadIndices* arrQuat);
	void Debug_NLerp2AimPose( CModelSkeleton* pModelSkeleton, SJointsAimIK_Rot* rRot,uint32 numRotJoints,  SJointsAimIK_Pos* rPos,uint32 numPosJoints, QuatT* arrRelPose0,QuatT* arrRelPose1,f32 t, QuatT*  arrAbsPose );
	void Debug_Blend4AimPose( CModelSkeleton* pModelSkeleton, SJointsAimIK_Rot* rRot,uint32 numRotJoints,  SJointsAimIK_Pos* rPos,uint32 numPosJoints, int8 i0,int8 i1,int8 i2,int8 i3, const Vec4& w, QuatT* arrRelPose,QuatT* arrAbsPose );

private:
	uint32 FlagsSanityFilter(uint32 flags);

public:
	string m_FilePath;					//path-name - unique per-model
	uint32 m_FilePathCRC32;			//hash value for searching animations

	uint16 m_nRef_by_Model;    //counter how many models are referencing this animation
	uint16 m_nRef_at_Runtime;  //counter how many times we use this animation at run-time at the same time (need for streaming)
	uint16 m_nTouchedCounter;  //do we use this asset at all?
	uint16 m_nControllers;	
	f32 m_fStartSec;					//Start time in seconds.
	f32 m_fEndSec;						//End time in seconds.
	f32 m_fTotalDuration;			//asset-feature: total duration in seconds.
	DynArray<IController_AutoPtr> m_arrController;
	uint32 m_AnimTokenCRC32;
	DynArray<AimIKPose> m_arrAimIKPosesAIM; //if this animation contains aim-poses, we store them here

	uint64 m_nExist;	
	Quat m_MiddleAimPoseRot;
	Quat m_MiddleAimPose;
	CHUNK_GAHAIM_INFO::VirtualExample m_PolarGrid[CHUNK_GAHAIM_INFO::XGRID*CHUNK_GAHAIM_INFO::YGRID];
	DynArray<CHUNK_GAHAIM_INFO::VirtualExampleInit2> VE2;
};




struct VExampleInit
{
	struct VirtualExampleInit1
	{
		f32 m_fSmalest;
		uint8 i0,i1,i2,i3;
		f64  w0,w1,w2,w3;
	};

	f64 m_fSmallest;
	uint32 m_nIterations;
	Vec4r m_Weight;

	int32  m_arrParentIdx[256];
	QuatT  m_arrDefaultRelPose[256];
	uint32 m_arrJointCRC32[256];

	QuatTr m_arrRelPose[256];
	QuatTr m_arrAbsPose[256];
	QuatTr m_arrRelPose0[256];
	QuatTr m_arrAbsPose0[256];
	QuatTr m_arrRelPose1[256];
	QuatTr m_arrAbsPose1[256];
	QuatTr m_arrRelPose2[256];
	QuatTr m_arrAbsPose2[256];
	QuatTr m_arrRelPose3[256];
	QuatTr m_arrAbsPose3[256];
	VirtualExampleInit1 PolarGrid[CHUNK_GAHAIM_INFO::XGRID*CHUNK_GAHAIM_INFO::YGRID];

	void Init(CModelSkeleton* pModelSkeleton,DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos,GlobalAnimationHeaderAIM& rAIM,int nWeaponBoneIdx,uint32 numAimPoses);
	void CopyPoses2(DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos, GlobalAnimationHeaderAIM& rAIM, uint32 numPoses, uint32 skey );
	void RecursiveTest( const Vec2r& ControlPoint, GlobalAnimationHeaderAIM& rAIM,DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos,int nWBone, int i0,int i1,int i2,int i3, const Vec4r& w0,const Vec4r& w1,const Vec4r& w2,const Vec4r& w3 );
	uint32 PointInQuat( const Vec2r& ControlPoint, GlobalAnimationHeaderAIM& rAIM,DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos,int nWBone, int i0,int i1,int i2,int i3, const Vec4r& w0,const Vec4r& w1,const Vec4r& w2,const Vec4r& w3 );

	uint32 LinesegOverlap2D(const Planer& plane0, const Vec2r& ls0,const Vec2r& le0,   const Vec2r& tp0,const Vec2r& tp1 );

	void ComputeAimPose( GlobalAnimationHeaderAIM& rAIM, CModelSkeleton* pModelSkeleton,DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos, QuatTr* arrAbsPose, uint32 nAimPose );
	void Blend4AimPose( GlobalAnimationHeaderAIM& rAIM, DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos, int8 i0,int8 i1,int8 i2,int8 i3, const Vec4r& w, QuatTr* arrRelPose,QuatTr* arrAbsPose );
	void NLerp2AimPose( DynArray<SJointsAimIK_Rot>& rRot,DynArray<SJointsAimIK_Pos>& rPos, QuatTr* arrRelPose0,QuatTr* arrRelPose1,f64 t, QuatTr* arrAbsPose );
	uint32 AnnotateExamples(uint32 numPoses, QuadIndices* arrQuat);
	Vec3r PolarCoordinate(const Quatr& q);
};




#endif
